/*!***************************************************
 * @file: func.h
 * @brief: 具体功能实现源文件
 * @author: ITHAO 
 * @date: 2018.12.7
 * @note: 
 ****************************************************/
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <stdbool.h>

#include "debug.h"
#include "func.h"

/*读写锁，用于处理多线程读写文件的并发*/
static pthread_rwlock_t friend_txt_rwmtx = PTHREAD_RWLOCK_INITIALIZER;
static pthread_rwlock_t chat_txt_rwmtx = PTHREAD_RWLOCK_INITIALIZER;

#define TRUE 1
#define FAIL 0

static void friend_init(struct friend *p_friend);
static bool save_user_friend(struct friend *p_friend);

/**
 * @brief	从文件中获取好友对应好友表         
 * @param	account--用户名
 *          p_friend--用于获取好友表的指针
 * @return	
 *          TRUE                        成功获取好友表
 *          FAIL                        没有对应用户信息
 */
bool load_friend(char *account, struct friend *p_friend)
{
    int ret = 0;
    FILE *fp = NULL;

    if (!account || !p_friend) {
        DEBUG("PARAM NULL!\r\n");
        return FAIL;
    }
    if (strlen(account) == 0) {
        DEBUG("PARAM NULL!\r\n");
        return FAIL;
    }

    fp = fopen(FRIEND_INFO_FILE, "ab+");
    if (!fp) {
        DEBUG("文件打开失败\n");
        return FAIL;
    }

    ret = FAIL;
    pthread_rwlock_rdlock(&friend_txt_rwmtx);
    while (!feof(fp)) {
        fread(p_friend, sizeof(struct friend), 1, fp);
        /*如果文件里面用对应用户名就可以退出了*/
        if(!strcmp(p_friend->owner_account, account)) {
            ret = TRUE;
            break;
        }       
    }
    pthread_rwlock_unlock(&friend_txt_rwmtx);
    if (ret == FAIL)
        friend_init(p_friend);

    fclose(fp);
    return ret;
}



/**
 * @brief	将指定用户加入好友表，
 *          如果是第一次加好友就生成好友信息          
 * @param	new_friend--新好友的的信息结构体
 *          owner_account--好友表拥有者用户账号
 * @return	-FUNC_PARAM_NULL_ERR        入口参数空
 *          -FUNC_SAVE_INFO_ERR         保存信息失败
 * 
 *          TRUE                        添加成功
 *          FUNC_EXCEED_FRIEND_NUM      好友数量满
 *          FUNC_IS_FRIEND_ALREADY      已经是好友
 */
int device_add_friend(struct friend_info new_friend, char *owner_account)
{
    int ret;
    struct friend friend_data;
    int count = 0;

    if (!owner_account) {
        DEBUG("PARAM NULL!\r\n");
        return (-FUNC_PARAM_NULL_ERR);
    }
    if (strlen(owner_account) == 0 ||
        strlen(new_friend.name)== 0 ||
        strlen(new_friend.account)== 0) {
        DEBUG("PARAM NULL!\r\n");
        return (-FUNC_PARAM_NULL_ERR);
    }

    ret = load_friend(owner_account, &friend_data);
    /*没有好友信息，初始化一个好友信息结构体*/
    if (ret == FAIL) {
        friend_init(&friend_data);
        strncpy(friend_data.owner_account,
                owner_account, ACCOUNT_MAX_LENGTH);
    /*有用户信息的话检查是否已经是好友*/
    } else {
        for (count = 0; count < MAX_FRIEND_NUM; count++) {
            if(!strcmp(new_friend.account, friend_data.info[count].account))
                return FUNC_IS_FRIEND_ALREADY;
        }
    }

    if (friend_data.friend_num == MAX_FRIEND_NUM)
        return FUNC_EXCEED_FRIEND_NUM;

    for (count = 0; count < MAX_FRIEND_NUM; count++) {
        if (friend_data.info[count].used_flag ==0) {
            strncpy(friend_data.info[count].name, 
                    new_friend.name, NAME_MAX_LENGTH);
            strncpy(friend_data.info[count].account, 
                    new_friend.account, ACCOUNT_MAX_LENGTH);
            friend_data.info[count].used_flag = 1;
            friend_data.friend_num ++;
            break;
        }
    }

    ret = save_user_friend(&friend_data);
    if (ret == FAIL)
        return (-FUNC_SAVE_INFO_ERR);

    LOG("用户 %s 添加好友 %s",
         owner_account, new_friend.account);
    return TRUE;
}

/**
 * @brief	将指定用户从好友表移除          
 * @param	friend_account--需要被删除的好友账号
 *          owner_account--好友表拥有者用户账号
 * @return	-FUNC_PARAM_NULL_ERR        入口参数空
 *          -FUNC_SAVE_INFO_ERR         保存信息失败
 * 
 *          TRUE                        删除成功
 *          FUNC_NO_OWNER_INFO         没有用户信息
 *          FUNC_NOT_FRIEND             与当前账号不是好友
 */
int device_remove_friend(char *friend_account, char *owner_account)
{
    int ret;
    struct friend friend_data;
    int count = 0;

    if (!friend_account || !owner_account) {
        DEBUG("PARAM NULL!\r\n");
        return (-FUNC_PARAM_NULL_ERR);
    }
    if (strlen(friend_account) == 0 ||
        strlen(owner_account)== 0) {
        DEBUG("PARAM NULL!\r\n");
        return (-FUNC_PARAM_NULL_ERR);
    }

    ret = load_friend(owner_account, &friend_data);
    if (ret == FAIL)
        return FUNC_NO_OWNER_INFO;

    if (friend_data.friend_num == 0)
        return FUNC_NOT_FRIEND;

    ret = FAIL;
    for (count = 0; count < MAX_FRIEND_NUM; count++) {
        if (friend_data.info[count].used_flag == 1) {
            if (!strcmp(friend_account, 
                        friend_data.info[count].account)) {
                ret = TRUE;
                friend_data.info[count].used_flag = 0;
                friend_data.friend_num--;
                memset(friend_data.info[count].name,
                         '\0', NAME_MAX_LENGTH);
                memset(friend_data.info[count].account,
                         '\0', ACCOUNT_MAX_LENGTH);
                break;
            }
        }
    }
    if (ret == FAIL)
        return FUNC_NOT_FRIEND;
    
    ret = save_user_friend(&friend_data);
    if (ret == FAIL)
        return (-FUNC_SAVE_INFO_ERR);

    LOG("用户 %s 删除好友 %s ",
         owner_account, friend_account);
    return TRUE;
}

/**
 * @brief	好友结构体初始化         
 * @param	p_friend--需要被初始化的数据
 * @return	void
 */
static void friend_init(struct friend *p_friend)
{
    int count;

    if (!p_friend) {
        DEBUG("PARAM NULL!\r\n");
        return;
    }

    memset(p_friend->owner_account, '\0', ACCOUNT_MAX_LENGTH);
    p_friend->friend_num = 0;

    for (count = 0; count < MAX_FRIEND_NUM; count++) {
        p_friend->info[count].used_flag = 0;
        memset(p_friend->info[count].name, '\0', NAME_MAX_LENGTH);
        memset(p_friend->info[count].account, '\0', ACCOUNT_MAX_LENGTH);
    }
}


/**
 * @brief	保存指定用户的好友表
 *          覆盖原有的好友表,如果没有就在文末写          
 * @param	p_friend--需要保存的好友表
 * @return	TRUE        保存成功
 *          FAIL        保存失败
 */
static bool save_user_friend(struct friend *p_friend)
{
    FILE *fp = NULL;
    struct friend tmp;
    long int offset = -1;

    if (!p_friend) {
        DEBUG("PARAM NULL!\r\n");
        return FAIL;
    }
    if (strlen(p_friend->owner_account) == 0) {
        DEBUG("PARAM NULL!\r\n");
        return FAIL;
    }

    fp = fopen(FRIEND_INFO_FILE, "ab+");
    if (!fp) {
        DEBUG("文件打开失败\n");
        return FAIL;
    }
    /*先找文件中是否已经有该用户的信息，有就返回信息的位置
      没有的话信息为负数*/
    pthread_rwlock_rdlock(&friend_txt_rwmtx);
    while (!feof(fp)) {
        fread(&tmp, sizeof(struct friend), 1, fp);
        /*如果文件里面用对应用户名就可以退出了*/
        if(!strcmp(tmp.owner_account, p_friend->owner_account)) {
            fseek(fp, -sizeof(struct friend), SEEK_CUR);
            offset = ftell(fp);
            break;
        } 
        offset = ftell(fp);      
    }
    pthread_rwlock_unlock(&friend_txt_rwmtx);
    fclose(fp);

    /*用写的方式打开，把数据写进去*/
    fp = fopen(FRIEND_INFO_FILE, "rb+");
    if (!fp) {
        DEBUG("文件打开失败\n");
        return FAIL;
    }
    pthread_rwlock_wrlock(&friend_txt_rwmtx);
 
    fseek(fp, offset, SEEK_SET);
    
    fwrite(p_friend, sizeof(struct friend), 1, fp);
    pthread_rwlock_unlock(&friend_txt_rwmtx);
    fclose(fp);

    return TRUE;
}


/**
 * @brief	初始化聊天包       
 * @param	p_chat_pakcet--聊天包结构体指针
 * @return	void
 */
void init_chat_packet(struct chat_packet *p_chat_pakcet)
{
    if (!p_chat_pakcet)
        return;

    memset(p_chat_pakcet, '\0', sizeof(struct chat_packet));
}


/**
 * @brief	保存聊天包       
 * @param	p_chat_pakcet--聊天包结构体指针
 * @return	TRUE 保存成功
 *          FAIL 保存失败
 */
bool save_chat_packet(const struct chat_packet *p_chat_pakcet)
{
    FILE *fp = NULL;
 
    if (!p_chat_pakcet) {
        DEBUG("PARAM NULL!\r\n");
        return FAIL;
    }

    /*用ab+打开以保证新数据写在文件末尾*/
    fp = fopen(UNSEND_CHAT_PACKET_FILE, "ab+");
    if (!fp) {
        DEBUG("文件打开失败\n");
        return FAIL;
    }

    pthread_rwlock_wrlock(&chat_txt_rwmtx);
    fprintf(fp, "%s\n%s\n%s\n%s\n%s\n", p_chat_pakcet->send_name,
                                        p_chat_pakcet->send_account,
                                        p_chat_pakcet->recv_account, 
                                        p_chat_pakcet->time, 
                                        p_chat_pakcet->msg);
    pthread_rwlock_unlock(&chat_txt_rwmtx);
    fclose(fp);

    return TRUE;
}

/**
 * @brief	找到指定接受账号的聊天包   
 * @param	p_chat_pakcet--聊天包结构体指针
 *          recv_account--接受账号   
 * @return	TRUE 有对应聊天包
 *          FAIL 无对应聊天包
 */
bool serch_chat_packet(char *recv_account,
                      struct chat_packet *p_chat_pakcet)
{
    int ret = FAIL;
    bool skip_once_flag = 0;
    FILE *fp = NULL;
    FILE *fp_tmp = NULL;
    struct chat_packet chat_packet_tmp;

    if (!p_chat_pakcet || !recv_account) {
        DEBUG("PARAM NULL!\r\n");
        return FAIL;
    }

    init_chat_packet(&chat_packet_tmp);

    fp = fopen(UNSEND_CHAT_PACKET_FILE, "ab+");
    if (!fp) {
        DEBUG("文件打开失败\n");
        return FAIL;
    }
    pthread_rwlock_rdlock(&chat_txt_rwmtx);
    while (!feof(fp)) {
        fgets(chat_packet_tmp.send_name, NAME_MAX_LENGTH, fp);
        fgets(chat_packet_tmp.send_account, ACCOUNT_MAX_LENGTH, fp);
        fgets(chat_packet_tmp.recv_account, ACCOUNT_MAX_LENGTH, fp);
        fgets(chat_packet_tmp.time, 26, fp);
        fgets(chat_packet_tmp.msg, MSG_MAX_LENGTH, fp);

        chat_packet_tmp.send_name[strlen(chat_packet_tmp.send_name) - 1] = '\0';
        chat_packet_tmp.send_account[strlen(chat_packet_tmp.send_account) - 1] = '\0';
        chat_packet_tmp.recv_account[strlen(chat_packet_tmp.recv_account) - 1] = '\0';
        chat_packet_tmp.time[strlen(chat_packet_tmp.time) - 1] = '\0';
        chat_packet_tmp.msg[strlen(chat_packet_tmp.msg) - 1] = '\0';

        if (!strncmp(chat_packet_tmp.recv_account, recv_account, strlen(recv_account))) {
            *p_chat_pakcet = chat_packet_tmp;
            ret = TRUE;
            break;
        }
    }
    pthread_rwlock_unlock(&chat_txt_rwmtx);
    fclose(fp);

    /*如果找到数据。把这一数据删掉*/
    if (ret == TRUE) {
        fp = fopen(UNSEND_CHAT_PACKET_FILE, "rb+");
        /*创建一个临时文件*/
        fp_tmp = fopen(TEMP_FILE, "ab+");

        pthread_rwlock_wrlock(&chat_txt_rwmtx);
        while (!feof(fp)) {
            if (fgets(chat_packet_tmp.send_name, NAME_MAX_LENGTH, fp) > 0
            && fgets(chat_packet_tmp.send_account, ACCOUNT_MAX_LENGTH, fp) > 0
            && fgets(chat_packet_tmp.recv_account, ACCOUNT_MAX_LENGTH, fp) > 0
            && fgets(chat_packet_tmp.time, 26, fp) > 0
            && fgets(chat_packet_tmp.msg, MSG_MAX_LENGTH, fp) > 0) {
                if (!strncmp(chat_packet_tmp.recv_account, recv_account, strlen(recv_account)) &&
                           skip_once_flag == 0) {
                    skip_once_flag = 1;
                    continue;
                }
                fprintf(fp_tmp, "%s%s%s%s%s", chat_packet_tmp.send_name,
                                                        chat_packet_tmp.send_account,
                                                        chat_packet_tmp.recv_account , 
                                                        chat_packet_tmp.time, 
                                                        chat_packet_tmp.msg);
            }
        }

        pthread_rwlock_unlock(&chat_txt_rwmtx);
        fclose(fp);
        fclose(fp_tmp);
        remove(UNSEND_CHAT_PACKET_FILE);
        rename(TEMP_FILE, UNSEND_CHAT_PACKET_FILE);
    }

    return ret;
}